package com.cencat.driver.config;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONReader;
import com.alibaba.fastjson2.JSONWriter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;
import org.springframework.data.redis.serializer.StringRedisSerializer;

import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;

/**
 * Redis配置类
 * 
 * @author cencat
 * @since 2024-01-01
 */
@Configuration
@EnableCaching
@ConfigurationProperties(prefix = "cache")
public class RedisConfig {

    /**
     * Redis缓存前缀
     */
    private String redisPrefix = "cencat:driver:";

    /**
     * 默认缓存过期时间（秒）
     */
    private long defaultTtl = 3600;

    /**
     * 司机信息缓存时间（秒）
     */
    private long driverInfoTtl = 1800;

    /**
     * 车辆信息缓存时间（秒）
     */
    private long vehicleInfoTtl = 1800;

    /**
     * 任务信息缓存时间（秒）
     */
    private long taskInfoTtl = 600;

    /**
     * RedisTemplate配置
     */
    @Bean
    public RedisTemplate<String, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<String, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // 使用StringRedisSerializer来序列化和反序列化redis的key值
        StringRedisSerializer stringRedisSerializer = new StringRedisSerializer();
        template.setKeySerializer(stringRedisSerializer);
        template.setHashKeySerializer(stringRedisSerializer);

        // 使用FastJSON2序列化器来序列化和反序列化redis的value值
        FastJson2RedisSerializer<Object> fastJson2RedisSerializer = new FastJson2RedisSerializer<>(Object.class);
        template.setValueSerializer(fastJson2RedisSerializer);
        template.setHashValueSerializer(fastJson2RedisSerializer);

        template.afterPropertiesSet();
        return template;
    }

    /**
     * 缓存管理器
     */
    @Bean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        // 默认缓存配置
        RedisCacheConfiguration defaultConfig = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(Duration.ofSeconds(defaultTtl))
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(new StringRedisSerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(new FastJson2RedisSerializer<>(Object.class)))
                .computePrefixWith(cacheName -> redisPrefix + cacheName + ":");

        // 不同缓存的配置
        Map<String, RedisCacheConfiguration> cacheConfigurations = new HashMap<>();
        
        // 司机信息缓存配置
        cacheConfigurations.put("driver", defaultConfig.entryTtl(Duration.ofSeconds(driverInfoTtl)));
        
        // 车辆信息缓存配置
        cacheConfigurations.put("vehicle", defaultConfig.entryTtl(Duration.ofSeconds(vehicleInfoTtl)));
        
        // 任务信息缓存配置
        cacheConfigurations.put("task", defaultConfig.entryTtl(Duration.ofSeconds(taskInfoTtl)));
        
        // 消息缓存配置
        cacheConfigurations.put("message", defaultConfig.entryTtl(Duration.ofSeconds(600)));
        
        // 统计信息缓存配置
        cacheConfigurations.put("stats", defaultConfig.entryTtl(Duration.ofSeconds(300)));

        return RedisCacheManager.builder(connectionFactory)
                .cacheDefaults(defaultConfig)
                .withInitialCacheConfigurations(cacheConfigurations)
                .build();
    }

    /**
     * FastJSON2 Redis序列化器
     */
    public static class FastJson2RedisSerializer<T> implements RedisSerializer<T> {

        private final Class<T> clazz;

        public FastJson2RedisSerializer(Class<T> clazz) {
            this.clazz = clazz;
        }

        @Override
        public byte[] serialize(T t) {
            if (t == null) {
                return new byte[0];
            }
            return JSON.toJSONString(t, JSONWriter.Feature.WriteClassName).getBytes(StandardCharsets.UTF_8);
        }

        @Override
        public T deserialize(byte[] bytes) {
            if (bytes == null || bytes.length <= 0) {
                return null;
            }
            String str = new String(bytes, StandardCharsets.UTF_8);
            return JSON.parseObject(str, clazz, JSONReader.Feature.SupportAutoType);
        }
    }

    // Getter and Setter methods
    public String getRedisPrefix() {
        return redisPrefix;
    }

    public void setRedisPrefix(String redisPrefix) {
        this.redisPrefix = redisPrefix;
    }

    public long getDefaultTtl() {
        return defaultTtl;
    }

    public void setDefaultTtl(long defaultTtl) {
        this.defaultTtl = defaultTtl;
    }

    public long getDriverInfoTtl() {
        return driverInfoTtl;
    }

    public void setDriverInfoTtl(long driverInfoTtl) {
        this.driverInfoTtl = driverInfoTtl;
    }

    public long getVehicleInfoTtl() {
        return vehicleInfoTtl;
    }

    public void setVehicleInfoTtl(long vehicleInfoTtl) {
        this.vehicleInfoTtl = vehicleInfoTtl;
    }

    public long getTaskInfoTtl() {
        return taskInfoTtl;
    }

    public void setTaskInfoTtl(long taskInfoTtl) {
        this.taskInfoTtl = taskInfoTtl;
    }
}